﻿#define SYNCLOGINFAIL

using System;
using System.Collections.Generic;
using System.Linq;
using YmtAuth.Domain.Model.LoginAuth;
using YmtAuth.Domain.Repository;
using YmtAuth.Dto;
using YmtSystem.CrossCutting;
using YmtAuth.Domain.Shard;
using Ymatou.User.Dto.Auth;
using Ymatou.User.Dto;
using YmtAuth.Domain.Repository.EventRepository;
using YmtAuth.Domain.Model.YmatouUser.Event;
using YmtAuth.LogService;
using YmtAuth.Repository.MSSQL;
using YmtAuth.AppService.ThirdPartyService;
using YmtAuth.Common;
using System.Threading.Tasks;
using ServiceStack.Web;
using YmtAuth.AppService.JavaService;

namespace YmtAuth.AppService
{
    public class UserBillsAppService : IUserBillsAppService
    {
        private IUserLoginBillsRepository UlBRepository { get { return LocalServiceLocator.GetService<IUserLoginBillsRepository>(); } }
        private ILoginIdUpdateEventRepository LoginIdUpdateEventRepo { get { return LocalServiceLocator.GetService<ILoginIdUpdateEventRepository>(); } }
        private ITokenAppService TokenAppService { get { return LocalServiceLocator.GetService<ITokenAppService>(); } }

        private IYmtUserPasswordChangeEventRepository UserBillsEventRepo { get { return LocalServiceLocator.GetService<IYmtUserPasswordChangeEventRepository>(); } }
        

        //创建凭据
        public ResponseData<string> CreateUserBills(Dictionary<string, object> uData = null)
        {
            try
            {
                YmtSystemAssert.AssertArgumentNotNull(uData, "用户数据不能为空");
                //
                //创建用户凭据
                var ulc = new UserLoginBill(uData);

                var deviceId = uData.TryGetV(YmtUserKey.sDeviceId, null) as string;
                var clientID = uData.TryGetV(YmtUserKey.sClientId, null) as string;
                var equimentid = uData.TryGetV(YmtUserKey.Equimentid, null) as string;

                YmatouLoggingService.Debug("创建用户凭据;  CreateUserBills, UserId: {0}, Mobile: {1}, RegSource: {2}, deviceId: {3}, clientID: {4}, equimentid: {5}", ulc.UserId,
                    ulc.LoginBills.Mobile, ulc.RegSource, deviceId, clientID, equimentid);

                if (UlBRepository.Exists(UserLoginAuthSpecifications.MatchLoginId(ulc.LoginBills.LoginId)))
                {
                    YmatouLoggingService.Debug("用户 {0} 存在，无法创建用户", ulc.LoginBills.LoginId);
                    return ResponseData<string>.CreateFail("用户存在无法创建");
                }
                if (!string.IsNullOrEmpty(ulc.LoginBills.Email) &&
                    UlBRepository.Exists(UserLoginAuthSpecifications.MatchLoginMail(ulc.LoginBills.Email)))
                {
                    YmatouLoggingService.Debug("用户 {0} 邮箱 {1} 存在，无法创建用户", ulc.LoginBills.LoginId, ulc.LoginBills.Email);
                    return ResponseData<string>.CreateFail("邮箱存在，无法创建用户");
                }
                if (!string.IsNullOrEmpty(ulc.LoginBills.Mobile) &&
                    UlBRepository.Exists(UserLoginAuthSpecifications.MatchLoginMobile(ulc.LoginBills.Mobile)))
                {
                    YmatouLoggingService.Debug("用户 {0} 手机 {1} 存在，无法创建用户", ulc.LoginBills.LoginId, ulc.LoginBills.Mobile);
                    return ResponseData<string>.CreateFail("手机存在，无法创建用户");
                }
                //save user bills
                UlBRepository.Add(ulc);
                //async save reg log
                var clientIp = uData.TryGetV(YmtUserKey.sClientIp, null) as string;
                LogTask.Instance.EnQueue(new UserRegisterHistory
                {
                    LoginId = ulc.LoginBills.LoginId,
                    UserId = ulc.UserId,
                    Mobile = ulc.LoginBills.Mobile,
                    LoginMail = ulc.LoginBills.Email,
                    ClientIp = clientIp,
                    RegSource = ulc.RegSource,
                    ChannelSource = uData.TryGetV(YmtUserKey.sChannelSource, null) as string,
                    TerminalSource = uData.TryGetV(YmtUserKey.sTerminalSource, null) as string,
                    DeviceId = deviceId,
                    Equimentid = equimentid                   
                });
                //保存用户常用IP区域
                UserSafeVerify.AddUserRegisterIpAreaAsync(clientIp, ulc.UserId, ulc.RegSource, 200);
                //保存用户设备号                
                UserSafeVerify.AddUserRegisterDeviceAsycn(deviceId, clientID, ulc.UserId, ulc.LoginBills.LoginId, ulc.RegSource,
                    clientIp,200);

                return ResponseData<string>.CreateSuccess("ok");
            }
            catch (Exception ex)
            {
                YmatouLoggingService.Error("创建用户凭据失败 -> {0}", ex);
                return ResponseData<string>.CreateFail(string.Format("创建用户凭据失败 {0}", ex.ToString()));
            }
        }

        // 获取用户凭据        
        public ResponseData<UserBillsResponseDto> GetUserBills(UserBillsRequestDto dto, IRequest request=null)
        {
            if (request != null)
            {
                if (RequestUserService.isSendReadToJavaUserService(dto, "UserBillsRequestDto", "GET", new string[] { dto.LoginId, dto.UserId.ToString() }))
                {
                    var result = RequestUserService.sendReadRequest<ResponseData<UserBillsResponseDto>>(dto, "UserBillsRequestDto", request.RawUrl, "GET",
                        request.QueryString);
                    if (result.isRequestSuccess) return result.resp;
                }
            }

            YmtSystemAssert.AssertArgumentNotNull(dto, "无效的UserBillsRequestDto");
            UserLoginBill userModel = null;

            //bool spread = false;

            //if (dto.UserId > 0)
            //    spread = ((Math.Abs(dto.UserId) % 10) + 1) <= ConfigUtility.SpreadUserBillsRate;
            //else if (!dto.LoginId.IsEmpty())
            //    spread = ((Math.Abs(dto.LoginId.GetHashCode()) % 10) + 1) <= ConfigUtility.SpreadUserBillsRate;
            //else if (!dto.Mail.IsEmpty())
            //    spread = ((Math.Abs(dto.Mail.GetHashCode()) % 10) + 1) <= ConfigUtility.SpreadUserBillsRate;
            //else if (!dto.Mobile.IsEmpty())
            //    spread = ((Math.Abs(dto.Mobile.GetHashCode()) % 10) + 1) <= ConfigUtility.SpreadUserBillsRate;            

            //ResponseData<BillsResponseDto> res = null;
            //BillsResponseDto bill = null;

            //string clientType = dto.ClientType == null ? "" : dto.ClientType;

            //using (var mm0 = Ymatou.PerfMonitorClient.MethodMonitor.New("auth_UserBillsRequestDto_" + clientType))
            //{
            //    if (spread && (dto.UserId > 0 || !dto.LoginId.IsEmpty()))
            //    {
            //        using (var mm = Ymatou.PerfMonitorClient.MethodMonitor.New("auth_Java_UserBills"))
            //        {
            //            res = UserAuthService.GetUserBills(dto);
            //        }

            //        //如果JAVA的获取用户凭据返回异常，使用.net的获取用户凭据
            //        if (!string.Equals("400", res.ErrorCode, StringComparison.InvariantCultureIgnoreCase))
            //        {
            //            if (res.Success && res.Result != null)
            //            {
            //                bill = res.Result;

            //                if (UserStatesAppService.CheckBlacklistUser(bill.LoginId).Item1 != UserStates.Normal)
            //                    return ResponseData<UserBillsResponseDto>.CreateFail(new UserBillsResponseDto { }, lastErrorMessage: "黑名单用户");

            //                var result = new UserBillsResponseDto
            //                {
            //                    LoginId = bill.LoginId,
            //                    LoginMail = bill.LoginEmail,
            //                    LoginMobile = bill.LoginMobile,
            //                    TPas = bill.TradingPas,
            //                    UserId = bill.UserId
            //                };

            //                return ResponseData<UserBillsResponseDto>.CreateSuccess(result, "ok");
            //            }
            //            else
            //            {
            //                return ResponseData<UserBillsResponseDto>.CreateFail(new UserBillsResponseDto { }, lastErrorMessage: "未找到用户");
            //            }
            //        }
            //    }
            //}            

            using (var mm = Ymatou.PerfMonitorClient.MethodMonitor.New("auth_Dotnet_UserBills"))
            {
                if (dto.UserId > 0)
                    userModel = UlBRepository.FindOne(UserLoginAuthSpecifications.MatchUserId(dto.UserId), true);
                else if (!dto.LoginId.IsEmpty())
                    userModel = UlBRepository.FindOne(UserLoginAuthSpecifications.MatchLoginId(dto.LoginId), true);
                else if (!dto.Mail.IsEmpty())
                    userModel = UlBRepository.FindOne(UserLoginAuthSpecifications.MatchLoginMail(dto.Mail), true);
                else if (!dto.Mobile.IsEmpty())
                    userModel = UlBRepository.FindOne(UserLoginAuthSpecifications.MatchLoginMobile(dto.Mobile), true);
            }
            
            if (userModel == null)
                return ResponseData<UserBillsResponseDto>.CreateFail(new UserBillsResponseDto { }, lastErrorMessage: "未找到用户");
            //是否被锁定
            if (userModel.IsLocked())
                return ResponseData<UserBillsResponseDto>.CreateFail(new UserBillsResponseDto { }, lastErrorMessage: "用户被锁定");
            if (!string.IsNullOrEmpty(dto.LoginPassword) && !userModel.CheckLoginPassword(dto.LoginPassword))
                return ResponseData<UserBillsResponseDto>.CreateFail(new UserBillsResponseDto { }, lastErrorMessage: "用户密码不匹配");
            //是否是黑名单用户
            if (UserStatesAppService.CheckBlacklistUser(userModel.LoginBills.LoginId).Item1 != UserStates.Normal)
                return ResponseData<UserBillsResponseDto>.CreateFail(new UserBillsResponseDto { }, lastErrorMessage: "黑名单用户");
            var responseDto = new UserBillsResponseDto
            {
                LoginId = userModel.LoginBills.LoginId,
                LoginMail = userModel.LoginBills.Email,
                LoginMobile = userModel.LoginBills.Mobile,
                TPas = userModel.TradingPassword,
                UserId = userModel.UserId

            };
            return ResponseData<UserBillsResponseDto>.CreateSuccess(responseDto, "ok");
        }

        public ResponseData<BillsResponseDto> GetUserBills(GetUserBillsRequestDto dto, IRequest request=null)
        {
            if (request != null)
            {
                if (RequestUserService.isSendReadToJavaUserService(dto, "GetUserBillsRequestDto", "GET", new string[] { dto.LoginId, dto.UserId.ToString() }))
                {
                    var result = RequestUserService.sendReadRequest<ResponseData<BillsResponseDto>>(dto, "GetUserBillsRequestDto", request.RawUrl, "GET",
                        request.QueryString);
                    if (result.isRequestSuccess) return result.resp;
                }
            }

            if (dto == null || (dto.LoginId.IsEmpty() && dto.UserId <= 0))
                return ResponseData<BillsResponseDto>.CreateFail(null, "400", "错误的请求参数");
            UserLoginBill userModel = null;
            if (dto.UserId > 0)
                userModel = UlBRepository.FindOne(UserLoginAuthSpecifications.MatchUserId(dto.UserId), true);
            else if (!dto.LoginId.IsEmpty())
                userModel = UlBRepository.FindOne(UserLoginAuthSpecifications.MatchLoginId(dto.LoginId), true);
            if (userModel == null)
                return ResponseData<BillsResponseDto>.CreateFail(null, "300", "用户不存在");
            if (userModel.IsLocked())
                return ResponseData<BillsResponseDto>.CreateFail(null, "100", "用户被锁定");

            var response = new BillsResponseDto
            {
                LoginId = userModel.LoginBills.LoginId,
                LoginEmail = userModel.LoginBills.Email,
                LoginMobile = userModel.LoginBills.Mobile,
                LoginPas = dto.IncludeLoginPas ? userModel.LoginPassword : null,
                UserId = userModel.UserId,
                TradingPas = dto.IncludeTps ? userModel.TradingPassword : null
            };
            return ResponseData<BillsResponseDto>.CreateSuccess(response);
        }

        //更新用户凭据      
        public ResponseData<LoginResponseCode> Update(UserBillsRequestDto dto)
        {
            YmtSystemAssert.AssertArgumentNotNull(dto, "无效的UserBillsRequestDto");
            var userModel = UlBRepository.FindOne(UserLoginAuthSpecifications.MatchUserId(dto.UserId), true);
            if (userModel == null)
                return ResponseData<LoginResponseCode>.CreateFail(LoginResponseCode.LoingIdOrPasError, lastErrorMessage: "未找到用户");

            //检查手机是否重复
            if (!string.IsNullOrEmpty(dto.Mobile)  /*&& !UlBRepository.Exists(UserLoginAuthSpecifications.MatchLoginMobile(dto.Mobile))*/)
                userModel.ChangLoginMobile(dto.Mobile);
            //检查油箱是佛重复
            if (!string.IsNullOrEmpty(dto.Mail) && !UlBRepository.Exists(UserLoginAuthSpecifications.MatchLoginMail(dto.Mail)))
                userModel.ChangLoginEmail(dto.Mail);
            //检查loginId是否重复
            if (dto.LoginId != DefaultBills.EmptyLoginId && !UlBRepository.Exists(UserLoginAuthSpecifications.MatchLoginId(dto.LoginId)))
            {
                userModel.ChangLoginId(dto.LoginId);
                if (dto.ActionSource == UserSource.App)
                    LoginIdUpdateEventRepo.AddAsync(new LoginIdUpdateEvent(dto.LoginId, userModel.UserId, userModel.LoginBills.Mobile, userSource: dto.ActionSource));
            }
            userModel.SetLocked(dto.Locked);
            UlBRepository.Save(userModel);
            return ResponseData<LoginResponseCode>.CreateSuccess(LoginResponseCode.OK, "ok");
        }

        public ResponseData<string> UpdateLoginId(LoginIdUpdateRequestDto dto)
        {
            if (dto == null || dto.UserId <= 0) return ResponseData<string>.CreateFail("", "400", "错误的数据请求");
            var userModel = UlBRepository.FindOne(UserLoginAuthSpecifications.MatchUserId(dto.UserId), true);
            if (userModel == null)
                return ResponseData<string>.CreateFail(string.Empty, lastErrorMessage: "未找到用户");
            userModel.LoginBills.SetLoginId(dto.LoginId,false);
            UlBRepository.Update(UserLoginAuthSpecifications.MatchUserId(dto.UserId),UserLoginAuthSpecifications.UpateUserLoginIdOrEmail(null,dto.LoginId));
            return ResponseData<string>.CreateSuccess("ok");
        }

        //锁定用户       
        public ResponseData<string> LockUser(LockUserRequestDto dto)
        {
            if (dto.Operating.IsEmpty() || dto.Description.IsEmpty()) return ResponseData<string>.CreateFail("fail", lastErrorMessage: "操作和操作说明不能为空");
            if (dto.UserId.IsEmpty()) return ResponseData<string>.CreateFail("fail", lastErrorMessage: "用户ID不能为空");
            UlBRepository.UpdateMulti(UserLoginAuthSpecifications.MathUserIdArray(dto.UserId), UserLoginAuthSpecifications.SetLocked());
            var dbResponse = UlBRepository.SetUserBillsSQLLockedStatus(dto.UserId, 1);
            dto.UserId.Each(u => LogTask.Instance.EnQueue(new UserLockLog { Description =  dto.Description,Operator = dto.Operating, UserId = u, LoginTime = DateTime.Now, OpType = UserLockLog.KefuLockedUser }));
            YmatouLoggingService.Debug("用户数据库锁定操作 userid: {0},op:{1},desc:{2},dbResposne:{3}", string.Join(",", dto.UserId), dto.Operating, dto.Description, dbResponse);

            Task.Factory.StartNew(() =>
            {
                dto.UserId.Each(u =>
                {
                    TokenAppService.RemoveToken(new UserRemoveTokenRequestDto() { UserId = u });
                });
            }).ContinueWith(t => { YmatouLoggingService.Error("LockUser - RemoveToken error", t.Exception); }, TaskContinuationOptions.OnlyOnFaulted);
            
            return ResponseData<string>.CreateSuccess("ok");
        }
        //解锁用户
        public ResponseData<string> UnLockUser(UnLockUserRequestDto dto)
        {
            if (dto.Operating.IsEmpty() || dto.Description.IsEmpty()) return ResponseData<string>.CreateFail("fail", lastErrorMessage: "操作和操作说明不能为空");
            if (dto.UserId.IsEmpty()) return ResponseData<string>.CreateFail("fail", lastErrorMessage: "用户ID不能为空");
            UlBRepository.UpdateMulti(UserLoginAuthSpecifications.MathUserIdArray(dto.UserId), UserLoginAuthSpecifications.SetUnLocked());
            var dbResponse = UlBRepository.SetUserBillsSQLLockedStatus(dto.UserId, 0);
            dto.UserId.Each(u => LogTask.Instance.EnQueue(new UserLockLog { Description = dto.Description, Operator = dto.Operating, UserId = u, LoginTime = DateTime.Now, OpType = UserLockLog.KefuUnLockedUser }));
            YmatouLoggingService.Debug("用户数据库锁定操作 userid: {0},op:{1},desc:{2},dbResposne:{3}", string.Join(",", dto.UserId), dto.Operating, dto.Description, dbResponse);
            return ResponseData<string>.CreateSuccess("ok");
        }
        //锁定IP
        public ResponseData<string> LockIp(LockIpRequestDto dto)
        {
            if (dto.Operating.IsEmpty() || dto.Description.IsEmpty()) return ResponseData<string>.CreateFail("fail", lastErrorMessage: "操作和操作说明不能为空");
            if (dto.Ip.IsEmpty()) return ResponseData<string>.CreateFail("fail", lastErrorMessage: "用户Ip不能为空");
            BlackListAppService.LockIp(dto.Ip, dto.LockdTimeOut);
            dto.Ip.Each(ip => LogTask.Instance.EnQueue(new UserLockLog { Description = dto.Description, Operator = dto.Operating, LoginIp = ip, LoginTime = DateTime.Now, OpType = UserLockLog.KefuLockedUserIp }));
            return ResponseData<string>.CreateSuccess("ok");
        }
        //解锁IP
        public ResponseData<string> UnLockIp(UnLockIpRequestDto dto)
        {
            YmatouLoggingService.Debug("[UnLockIp] {0}", dto.ToString());
            
            if (dto.Operating.IsEmpty() || dto.Description.IsEmpty()) return ResponseData<string>.CreateFail("fail", "100", "操作和操作说明不能为空");
            if (dto.Ip.IsEmpty()) return ResponseData<string>.CreateFail("fail","300", "用户Ip不能为空");
            
            //默认是为买家解锁IP
            if (dto.IpType <= 0) dto.IpType = 1;

            int ipType = dto.IpType;

            BlackListAppService.UnLockIp(dto.Ip, ipType);

            foreach (var ip in dto.Ip)
            {
                RepositoryDependencies.UserLoginIpCountRepository.Invoke().ResetLatestLoginIPCount(ip, ipType);
                LogTask.Instance.EnQueue(new UserLockLog { Description = dto.Description, Operator = dto.Operating, LoginIp = ip, LoginTime = DateTime.Now, OpType = UserLockLog.KefuUnLockedUserIp });
            }

            return ResponseData<string>.Create("ok", true, "", "200");
        }
        //查看锁定状态
        public ResponseData<IDictionary<int, string>> GetUserLockStatus(UserLockStatusRequestDto dto)
        {
            if (dto.UserIdString.IsEmpty()) return ResponseData<IDictionary<int, string>>.CreateFail(null, lastErrorMessage: "用户ID不能为空");
            var useridArray =dto.UserIdString.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries)
                                .Select(u => Convert.ToInt32(u));
            var dic = UlBRepository.Find(UserLoginAuthSpecifications.MathUserIdArray(useridArray)).ToDictionary(u => u.UserId, u => u.Locked);
            var lockInfo = UlBRepository.FindUserLockdInfo(dic.Select(k => k.Key).ToArray());
            var tmpDic=new Dictionary<int,string>();
            foreach (var info in lockInfo)
            {
                tmpDic[info.Item1] = string.Format("{0},{1}",dic[info.Item1],info.Item2);
            }           
            var subUid = tmpDic.Keys.Except(dic.Keys);
            var _subuid = subUid.IsEmpty() ? dic.Keys.Except(tmpDic.Keys) : subUid;
            foreach (var uid in _subuid)
            {
                tmpDic[uid] = string.Format("{0}", dic[uid]);
            }
            return ResponseData<IDictionary<int, string>>.CreateSuccess(tmpDic);
        }
        public ResponseData<IDictionary<string, bool>> GetIpLockStatus(IpLockStatusRequestDto dto)
        {
            if (dto.IpString.IsEmpty()) return ResponseData<IDictionary<string, bool>>.CreateFail(null, lastErrorMessage: "Ip不能为空");
            var ipArray = dto.IpString.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
            var dic = BlackListAppService.FindRequestIPList(ipArray).ToDictionary(k => k.Id, v => v.IsDisableRequest());
            return ResponseData<IDictionary<string, bool>>.CreateSuccess(dic);
        }

        /// <summary>
        /// 获取用户密码的上次更新时间    
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public ResponseData<string> GetLastUpdatedTimeForPas(UserBillsPasRequestDto dto, IRequest request = null)
        {

            if (request != null)
            {
                if (RequestUserService.isSendReadToJavaUserService(dto, "UserBillsPasRequestDto", "GET", new string[] { dto.UserId.ToString() }))
                {
                    var result = RequestUserService.sendReadRequest<ResponseData<string>>(dto, "UserBillsPasRequestDto", request.RawUrl, "GET",
                        request.QueryString);
                    if (result.isRequestSuccess) return result.resp;
                }
            }

            YmtSystemAssert.AssertArgumentNotNull(dto, "无效的UserBillsPasRequestDto");
            YmatouLoggingService.Debug("获取用户密码的上次更新时间, GetLastUpdatedTimeForPas; PType: {0}, UserId: {1}", dto.PType, dto.UserId);

            string lastUpdatedTime = string.Empty;
            if (dto.PType != 1 && dto.PType != 2) return ResponseData<string>.CreateFail(null, "400", "用户密码类型错误, PType: " + dto.PType);
            if (dto.UserId <= 0) return ResponseData<string>.CreateFail(null, "400", "用户ID错误, UserId: " + dto.UserId);

            string pType = dto.PType == 1 ? "lpas" : "tpas";
            var pasUpdateHistory = UserBillsEventRepo.Find(UserBillsSpecifications.MatchPasUpdateHistory(dto.UserId, pType));

            if (pasUpdateHistory == null || !pasUpdateHistory.Any())
                return ResponseData<string>.CreateFail(lastUpdatedTime, "404", string.Format("未找到密码更新记录, PType: {0}, UserId: {1}", dto.PType, dto.UserId));

            lastUpdatedTime = pasUpdateHistory.Select(r => r.ModifyTime).Max().ToLocalTime().ToString();

            return ResponseData<string>.CreateSuccess(lastUpdatedTime, "ok");
        }
    }
}
